

/**
 * 数学相关类，由于本引擎是一个 2D 游戏引擎，所以内置的 Point 只有 x,y 两个属性，并且矩阵是个 3*3 矩阵
 */

 /**
  * point [x,y,1]
  * 
  * Matrix 
  * [a   c   tx]
  * [b   d   ty]
  * [0   0    1]
  */


/**
 * 表示一个点，也等价于一个二维向量  
 */  
class Point {
    x;
    y;
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
}

/**
 * 
 * 向量与矩阵相乘
 * 其几何意义是：
 * 把一个点的坐标（向量）进行一个空间变换（矩阵），得到一个新的坐标（向量）
 */ 
 //点左乘矩阵
function pointAppendMatrix(point, m) {
    var x = m.a * point.x + m.c * point.y + m.tx;
    var y = m.b * point.x + m.d * point.y + m.ty;
    return new Point(x, y);

}


/**
 * 使用伴随矩阵法求逆矩阵
 * http://wenku.baidu.com/view/b0a9fed8ce2f0066f53322a9
 */

function invertMatrix(m) {


    var a = m.a;
    var b = m.b;
    var c = m.c;
    var d = m.d;
    var tx = m.tx;
    var ty = m.ty;

    var determinant = a * d - b * c;
    var result = new Matrix(1, 0, 0, 1, 0, 0);
    if (determinant == 0) {
        throw new Error("no invert");
    }

    determinant = 1 / determinant;
    var k = result.a = d * determinant;
    b = result.b = -b * determinant;
    c = result.c = -c * determinant;
    d = result.d = a * determinant;
    result.tx = -(k * tx + c * ty);
    result.ty = -(b * tx + d * ty);
    return result;

}

/**
 * 
 * 矩阵与矩阵相乘
 * 扩展阅读：矩阵乘法的几何意义是什么？ 
 * https://www.zhihu.com/question/21351965/answer/204058188
 */
function matrixAppendMatrix(m1, m2) {

    var result = new Matrix();
    result.a = m1.a * m2.a + m1.b * m2.c;
    result.b = m1.a * m2.b + m1.b * m2.d;
    result.c = m2.a * m1.c + m2.c * m1.d;
    result.d = m2.b * m1.c + m1.d * m2.d;
    result.tx = m2.a * m1.tx + m2.c * m1.ty + m2.tx;
    result.ty = m2.b * m1.tx + m2.d * m1.ty + m2.ty;
    return result;
}

var PI = Math.PI;
var HalfPI = PI / 2;
var PacPI = PI + HalfPI;
var TwoPI = PI * 2;
var DEG_TO_RAD = Math.PI / 180;





class Matrix {

    a = 1;
    b = 0;
    c = 0;
    d = 1;
    tx = 0;
    ty = 0;

    constructor(a = 1, b = 0, c = 0, d = 1, tx = 0, ty = 0) {
        this.a = a;
        this.b = b;
        this.c = c;
        this.d = d;
        this.tx = tx;
        this.ty = ty;
    }



    /**
     * 返回将 Matrix 对象表示的几何转换应用于指定点所产生的结果。
     */
    toString() {
        return "(a=" + this.a + ", b=" + this.b + ", c=" + this.c + ", d=" + this.d + ", tx=" + this.tx + ", ty=" + this.ty + ")";
    }

    /**
     * 根据显示对象的属性确定当前矩阵
     */
    updateFromDisplayObject(x, y, scaleX, scaleY, rotation) {

        this.tx = x;
        this.ty = y;

        var skewX, skewY;
        skewX = skewY = rotation / 180 * Math.PI;;

        var u = Math.cos(skewX);
        var v = Math.sin(skewX);
        this.a = Math.cos(skewY) * scaleX;
        this.b = Math.sin(skewY) * scaleX;
        this.c = -v * scaleY;
        this.d = u * scaleY;

    }
}

/**
 * 检查点是否在矩阵内 
 */
function checkPointInRectangle(point, rectangle) {
    return (
        point.x >= rectangle.x &&
        point.x <= rectangle.x + rectangle.width &&
        point.y >= rectangle.y &&
        point.y <= rectangle.y + rectangle.height
    )
}

/**
 * 取绝对值
 */
function Abs(result) {
    return result >= 0 ? result : -result;
}

/**
 * 平方
 */
function Square(x) {
    return x * x;
}

/**
 * 取较小值
 */
function getMin(a, b) {
    return a > b ? b : a;
}
/**
 * 取较大值
 */
function getMax(a, b) {
    return a < b ? b : a;
}